using System;
using Source.Common;


namespace EntityFramework.ServiceLayer
{
    public interface IActiveObjectContextManager
    {
        /// <summary>
        /// Returns the active ObjectContext for the current thread. Throws exception if there's no active ObjectContext instance.
        /// </summary>
        /// <returns>ObjectContext</returns>
        IObjectContext GetActiveObjectContext();

        /// <summary>
        /// Sets the active ObjectContext for the current thread. Throws exception if there's already an active ObjectContext instance.
        /// </summary>
        /// <param name="objectContext"></param>
        void SetActiveObjectContext(IObjectContext objectContext);

        /// <summary>
        /// Clears the active ObjectContext for the current thread.
        /// </summary>
        void ClearActiveObjectContext();

        /// <summary>
        /// Returns true if an active ObjectContext is present, false if not.
        /// </summary>
        bool HasActiveObjectContext { get; }
    }

    public class ActiveObjectContextManager : IActiveObjectContextManager
    {
        [ThreadStatic]
        private static IObjectContext current;
        private const string objectContextKey = "_currentObjectContext";
        private readonly IRequestState requestState;

        public ActiveObjectContextManager() : this(null) { }

        public ActiveObjectContextManager(IRequestState requestState)
        {
            this.requestState = requestState;
        }

        public IObjectContext GetActiveObjectContext()
        {
            if (Current == null)
            {
                throw new InvalidOperationException("There is not active ObjectContext instance for this thread.");
            }

            return Current;
        }

        public void SetActiveObjectContext(IObjectContext objectContext)
        {
            if (Current != null)
            {
                throw new InvalidOperationException("There is already an active ObjectContext instance for this thread.");
            }

            Current = objectContext;
        }

        public void ClearActiveObjectContext()
        {
            Current = null;
        }

        public bool HasActiveObjectContext
        {
            get { return Current != null; }
        }

        protected virtual IObjectContext Current
        {
            get
            {
                if (requestState != null)
                {
                    return requestState.Get<IObjectContext>(objectContextKey);
                }

                return current;
            }
            set
            {
                if (requestState != null)
                {
                    requestState.Store(objectContextKey, value);
                }
                else
                {
                    current = value;
                }
            }
        }
    }
}